package com.ibm.risk.irmp.common.auth.oauth2.welink;

import com.ibm.risk.irmp.common.auth.JWTFilter;
import com.ibm.risk.irmp.common.auth.oauth2.LoginBaseProcessor;
import com.ibm.risk.irmp.common.auth.vo.LoginUser;
import com.ibm.risk.irmp.common.exception.AuthenticationException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static com.ibm.risk.irmp.common.auth.oauth2.welink.WeLinkOAuth2SSOProcessor.USER_ID_KEY;
import static com.ibm.risk.irmp.common.auth.sso.SSOProcessor.AUTH_COOKIE_NAME;

@Slf4j
@Component
public class WelinkNologProcessor extends LoginBaseProcessor {


    public void processNolog(HttpServletRequest request, HttpServletResponse response) {
        if (request.getMethod().equals(HttpMethod.GET.name())) {
            //第四步、获取access_token
            String token = getAccessToken(request);
            //第五步、获取userId
            Map<String, Object> userInfo = getUserInfo(request, token);
            //第六步、获取用户详细信息
            if (!validUserInfo(userInfo)) {
                log.error("User info is invalid: {}", userInfo);
                throw new AuthenticationException("User info is invalid");
            }
            String userKey = (String) userInfo.get(configuration.getUserNameAttribute());
            log.info("user id: {}", userKey);
            if (userKey == null && !StringUtils.isEmpty(configuration.getUserDetailUri())) {
                Map<String, Object> userDetailAttrs = getUserDetail(request, token, userInfo);
                if (!validUserDetail(userDetailAttrs)) {
                    log.error("User detail is invalid: {}", userDetailAttrs);
                    throw new AuthenticationException("User detail is invalid");
                }
                log.info("user detail: {}", userDetailAttrs);
                userKey = (String) userDetailAttrs.get(configuration.getUserNameAttribute());
            }
            if (userKey == null) {
                log.error("User name attribute [{}] not found in user info and detail: {}", configuration.getUserNameAttribute(), userInfo);
                throw new AuthenticationException("User name attribute [" + configuration.getUserNameAttribute() + "] not found in user info and detail ");
            }
//        try {
            LoginUser userByUserSSOKey = userService.getUserByUserSSOKey(userKey);
            if (userByUserSSOKey == null) {
                log.error("User not found: {}", userKey);
                throw new AuthenticationException("User not found");
            }
            userSessionStore.setLoginUser(token, userByUserSSOKey);

            request.setAttribute(AUTH_COOKIE_NAME, token);
            JWTFilter.setAuthHeader(token, response);
        }
    }
    public String getAccessToken(HttpServletRequest request) {
        RequestEntity<?> requestEntity = getTokenRequestV2();
        ResponseEntity<Map<String, Object>> respMap = getResponse(requestEntity);
        String token = (String) respMap.getBody().get("access_token");
        if (token == null) {
            log.error("Error to get token, responsed:{}", respMap.getBody());
            throw new AuthenticationException("Error to get token.");
        }
        return token;
    }
    protected RequestEntity<?> getTokenRequestV2() {
        //第四步、获取access_token
        /*
        请求地址： https://open.welink.huaweicloud.com/api/auth/v2/tickets
        请求头部
        Content-Type: application/json
        请求参数：
        {
          "client_id": "20190828163922073733756",
          "client_secret": "7c4f1e6e-f2db-42bd-a2c1-b2905c1c2a5b"
        }
         */
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        String tokenUri2 = configuration.getTokenUri2();
        log.debug("Request token url: {}", tokenUri2);
        URI uri = UriComponentsBuilder
                .fromUriString(tokenUri2).build().toUri();
        RequestEntity<?> request;
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, String> formParameters = new HashMap<>();
        formParameters.put("client_id", configuration.getClientId());
        formParameters.put("client_secret", configuration.getClientSecret());
        try {
            request = new RequestEntity<>(formParameters, headers, HttpMethod.POST, uri);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return request;
    }

    @Override
    public RequestEntity<?> getUserIdRequest(String token, String code) {

        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        URI uri = UriComponentsBuilder
                .fromUriString(configuration.getUserInfoUri2().replace("{code}", code)).build().toUri();
        RequestEntity<?> request;
//        if (HttpMethod.POST.equals()) {
//            headers.setContentType(DEFAULT_CONTENT_TYPE);
//            MultiValueMap<String, String> formParameters = new LinkedMultiValueMap<>();
//            formParameters.add(OAuth2ParameterNames.ACCESS_TOKEN, userRequest.getAccessToken().getTokenValue());
//            request = new RequestEntity<>(formParameters, headers, httpMethod, uri);
//        } else {
        setAuthToken(headers, token);
        request = new RequestEntity<>(headers, HttpMethod.GET, uri);
//        }

        return request;
    }

    @Override
    protected void setAuthToken(HttpHeaders headers, String token) {
        headers.set("x-wlk-Authorization", token);
    }

    protected boolean validUserInfo(Map<String, Object> userInfo) {
        return userInfo != null && userInfo.containsKey(USER_ID_KEY);
    }
    protected boolean validUserDetail(Map<String, Object> userDetail) {
        return userDetail != null && userDetail.containsKey(USER_ID_KEY);
    }
    protected Map<String, Object> getUserDetail(HttpServletRequest request, String token, Map<String, Object> userId) {
        RequestEntity<?> detailRequest = getUserDetailRequest(token, userId);
        return getResponse(detailRequest).getBody();
    }

    //TODO: duplicated code
    public RequestEntity<?> getUserDetailRequest(String token, Map<String, Object> userId) {

        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        StringBuilder userDetailUri = new StringBuilder(configuration.getUserDetailUri());
        userId.forEach((k, v) -> {
            String replaceHolder = "{" + k + "}";
            int idx = userDetailUri.indexOf(replaceHolder);
            if (idx >= 0) {
                userDetailUri.replace(idx, idx + replaceHolder.length(), v.toString());
            }
        });
        URI uri = UriComponentsBuilder
                .fromUriString(userDetailUri.toString()).build().toUri();

        RequestEntity<?> request;
//        if (HttpMethod.POST.equals()) {
//            headers.setContentType(DEFAULT_CONTENT_TYPE);
//            MultiValueMap<String, String> formParameters = new LinkedMultiValueMap<>();
//            formParameters.add(OAuth2ParameterNames.ACCESS_TOKEN, userRequest.getAccessToken().getTokenValue());
//            request = new RequestEntity<>(formParameters, headers, httpMethod, uri);
//        } else {
        setAuthToken(headers, token);
        request = new RequestEntity<>(headers, HttpMethod.POST, uri);
//        }

        return request;
    }

}
